<!--
需要权限的上传下载文件URI
https://xzqtsg.net/api/file/upload
https://xzqtsg.net/api/file/upload-multi
https://xzqtsg.net/api/file/download/stream/{uuid}
https://xzqtsg.net/api/file/download/entity/{uuid}
https://xzqtsg.net/api/file/image/{uuid}
对外公开的上传下载文件URI
https://xzqtsg.net/api-public/file/download/stream/{uuid}
https://xzqtsg.net/api-public/file/download/entity/{uuid}
https://xzqtsg.net/api-public/file/image/{uuid}

本组件实现手动上传多个非图片文件到图书馆服务器的功能，常用于文章内容页上传多个附件
1、选择要上传的文件，一次可以选多个文件
2、对文件格式和大小进行验证，并给出提示
3、点击按钮上传到服务器，返回上传结果数组
返回的结果是
[
  'https://xzqtsg.net/api-public/file/download/entity/{uuid}',
  'https://xzqtsg.net/api-public/file/download/entity/{uuid}'
]
-->
<template>
  <div class="wrapper-uploader">
    <el-button icon="UploadFilled" size="small" type="success" @click="flagDialogUpload = true">
      上传附件
    </el-button>
    <el-dialog title="选择本地文件上传到服务器，一次最多选 5 个文件！" v-model="flagDialogUpload">
      <el-upload
        ref="theUploader"
        :auto-upload="false"
        action="void"
        :data="paramsJson"
        :headers="headerJwt"
        :class="{ hide: flagHideUploader }"
        :show-file-list="true"
        :file-list="selectedFileList"
        list-type="text"
        :limit="5"
        multiple
        :on-exceed="onExceed"
        :on-change="onChange"
        :on-remove="onRemove"
      >
        <el-icon><Plus /></el-icon>
      </el-upload>
      <template #footer>
        <el-button @click="flagDialogUpload = false">取消</el-button>
        <el-button type="primary" @click="submitUpload">确定上传</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import { getAdminId } from '@/utils/common'
import { getJwtFromCookie } from '@/utils/jwt'
import { getLStorageObj } from '@/utils/web-storage'
import { validUploadFiles } from '@/utils/file'
import { toastSuccess, toastError } from '@/utils/toast'

import router from '@/router'
import store from '@/store'
import { defineComponent, ref, onMounted, computed } from 'vue'
export default defineComponent({
  name: 'UploadFilesCom',
  props: {},
  emit: ['update:setUploadResult'],
  setup(props, { emit }) {
    const uploadConfig = ref(null)
    // const urlPrefixShowIIS = ref(process.env.VUE_APP_BASE_DOMAIN_SHOW_UPLOAD_FILE_PREFIX)
    // 显示上传框
    const flagDialogUpload = ref(false)
    // 当选择满了文件后隐藏选择文件按钮要用到的判断变量
    const flagHideUploader = ref(false)
    // 上传成功后的服务器返回信息存到此变量中
    const uploadResultList = ref([])
    // 选中的文件列表，注意：这个变量不是双向绑定的，要在onChange方法里对其进行赋值
    const selectedFileList = ref([])

    const headerJwt = computed(() => {
      return { authorization: 'Bearer ' + getJwtFromCookie() }
    })
    const paramsJson = computed(() => {
      return { Id: 0, Type: 'Admin', FormData: null }
    })
    // 获取管理员id
    const getIdAdmin = () => {
      paramsJson.value.Id = getAdminId()
    }
    // 获取上传设置
    const getConfigUpload = () => {
      uploadConfig.value = getLStorageObj('UploadConfig')
      // 检验上传配置是否已设置，如果没有，跳回登录页
      if (!uploadConfig.value) {
        toastError('读取上传配置出错！')
        router.push({ path: '/login' })
      }
    }
    // 在onChange前执行，文件超出个数限制时的钩子，这个限制是 limit 属性设定的
    const onExceed = () => {
      // console.log('onExceed files', files)
      // console.log('onExceed fileList', fileList)
      // files 是选中的硬盘上的文件数组
      // fileList 是组件里已选中的文件数组
      // 已选中的文件数组长度+选中的硬盘上的文件数组的长度>limit属性值，才表示超出个数限制
      toastError('一次最多上传 5 个文件')
    }
    // 文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
    // 经过调试，选了3个文件，这个方法会执行3次
    // 要执行多次，所以验证文件不放在这里
    const onChange = (file, fileList) => {
      // console.log('onChange file', file)
      selectedFileList.value = validUploadFiles(
        fileList,
        uploadConfig.value.allowedExtImg,
        uploadConfig.value
      )
      // console.log('onchange selectedFileList', selectedFileList.value)
      flagHideUploader.value = fileList.length >= 5
    }
    // 文件列表移除文件时的钩子，此时无需返回值给父组件
    const onRemove = (file, fileList) => {
      // console.log('onRemove file', file)
      selectedFileList.value = fileList
      flagHideUploader.value = fileList.length >= 5
    }

    // 手动上传，要点击上传按钮才上传，并且 onBeforeUpload、onSuccess 都不执行
    const submitUpload = () => {
      // 验证是否为空
      if (selectedFileList.value.length === 0) {
        toastError('请选择要上传的文件!')
        return false
      }
      var formData = new FormData()
      selectedFileList.value.forEach((file) => {
        formData.append('files', file.raw)
      })
      paramsJson.value.FormData = formData
      store
        .dispatch('sys_ul_file/uploadFileMulti', paramsJson.value)
        .then((response) => {
          if (response) {
            console.log('上传成功后的response', response)
            const resultList = response
            for (let i = 0; i < resultList.length; i++) {
              // uploadResultList.value.push(resultList[i].uuid)
              uploadResultList.value.push(resultList[i])
            }
            toastSuccess('文件上传成功!')
            // 将结果返回给调用此组件的父组件
            returnUploadResult(uploadResultList.value)
            // 清空已选文件列表
            selectedFileList.value = []
            // 清空已上传的文件列表
            uploadResultList.value = []
            // 显示选择本地文件按钮
            flagHideUploader.value = false
            // 关闭上传dialog
            flagDialogUpload.value = false
          } else {
            toastError('服务器错误！上传失败！')
          }
        })
        .catch((error) => {
          console.log('上传文件时API返回错误:', error)
          toastError(error)
          // 将结果返回给调用此组件的父组件
          returnUploadResult([])
          flagDialogUpload.value = true
        })
    }

    const returnUploadResult = (val) => {
      // 调用本组件时，组件设置一个方法 @setUploadResult="getUploadResult($event)"
      // 父组件中定义一个名称为 getUploadResult 的方法，方法的参数值就是这里返回的上传结果
      emit('setUploadResult', val)
    }

    onMounted(() => {
      getIdAdmin()
      getConfigUpload()
    })
    return {
      uploadConfig,
      // urlPrefixShowIIS,
      flagDialogUpload,
      flagHideUploader,
      uploadResultList,
      selectedFileList,
      headerJwt,
      paramsJson,
      getIdAdmin,
      getConfigUpload,
      onExceed,
      onChange,
      onRemove,
      submitUpload,
      returnUploadResult,
    }
  },
})
</script>

<style lang="scss" scoped>
:deep(.el-upload--text) {
  cursor: pointer;
  background-color: #fbfdff;
  border: 1px dashed #c0ccda;
  width: 60px;
  height: 60px;
}
.hide {
  :deep(.el-upload--text) {
    display: none;
  }
}
</style>
